package engine.fov;

import java.util.List;
import java.util.Vector;

/**
 * Bresenham LOS class. Checks if a bresenham line can be drawn from source to destination.
 * 
 * @author sdatta
 */
public class BresLos implements ILosAlgorithm {

	/**
	 * Stores the path a projectile could take from the starting point to the ending point, if one
	 * exists.
	 */
	private Vector<Point2I> path;

	/**
	 * See the constructor's Javadoc
	 */
	boolean symmetricEnabled = false;

	/**
	 * @param symmetric
	 *            If symmetric is true, also checks the alternate Bresenham line from destination to
	 *            source, ensuring that ranged combat is fair (if I can shoot you then you can shoot
	 *            me.) Surprisingly enough this is actually an issue in some games, where it is
	 *            possible to hide behind a pillar and shoot enemies safely.
	 */
	public BresLos(boolean symmetric) {
		symmetricEnabled = symmetric;
	}

	public boolean existsLineOfSight(Board b, int startX, int startY, int x1, int y1,
			boolean calculateProject) {
		final int dx = startX - x1, dy = startY - y1;
		final int adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy;
		final int len = (adx > ady ? adx : ady) + 1;// Max number of points on
		// the
		// path.

		if (calculateProject) {
			path = new Vector<Point2I>(len);
		}

		// array to store path.
		final int[] px = new int[len], py = new int[len];

		// Start to finish path
		BresenhamLine.plot(startX, startY, x1, y1, px, py);

		boolean los = false;
		for (int i = 0; i < len; i++) {
			if (calculateProject) {
				path.add(new Point2I(px[i], py[i]));
			}
			if (px[i] == x1 && py[i] == y1) {
				los = true;
				break;
			}
			if (b.isObstruction(px[i], py[i])) {
				break;
			}
		}
		// Direct path couldn't find LOS so try alternate path
		if (!los && symmetricEnabled) {
			int[] px1 = null, py1 = null;
			// allocate space for alternate path
			px1 = new int[len];
			py1 = new int[len];
			// finish to start path.
			BresenhamLine.plot(x1, y1, startX, startY, px1, py1);

			final Vector<Point2I> oldpath = path;
			path = new Vector<Point2I>(len);
			for (int i = len - 1; i > -1; i--) {
				if (calculateProject) {
					path.add(new Point2I(px1[i], py1[i]));
				}
				if (px1[i] == x1 && py1[i] == y1) {
					los = true;
					break;
				}
				if (b.isObstruction(px1[i], py1[i])) {
					break;
				}
			}

			path = oldpath.size() > path.size() ? oldpath : path;
		}

		return los;
	}

	public List<Point2I> getProjectPath() {
		return path;
	}
}
